﻿using System;
using System.Collections.Generic;
using System.Linq;
using DataFiller.DataStorage.Holders;
using DataFiller.DataStorage.Interpreters;
using DataFiller.DataStorage.Regions;

namespace DataFiller.DataStorage.Store
{
    public abstract class DataMap<T> : IDataMap<T>
    {
        protected Dictionary<T, IDataRegion<T>> _Resgions;
        protected InterpreterContainer _InterpreterContainer;

        public DataMap()
        {
            _Resgions = new Dictionary<T, IDataRegion<T>>();
        }

        #region IDataStore<T> Members
        public virtual void FeedData(T key, IDataHolder holder)
        {
            IDataRegion<T> region = RegionChecking(key);
            if (region == null)
                throw new ArgumentException(string.Format("given key {0} is not existing.", key));

            FeedingData(holder, region);
        }
        public void RegistInterpreterContainer(InterpreterContainer iContainer)
        {
            _InterpreterContainer = iContainer;
        }
        public virtual void AddRegion(T key, IDataRegion<T> region)
        {
            if (_Resgions == null)
                _Resgions = new Dictionary<T, IDataRegion<T>>();
            else if (_Resgions.ContainsKey(key))
                throw new ArgumentException(string.Format("given key {0} is already existing.", key));

            //process the data that already existing in given region
            IDataHolder[] tempHolder = new IDataHolder[region.Records.Count];
            region.Records.CopyTo(tempHolder);
            foreach (var holder in tempHolder)
            {
                FeedingData(holder, region);
            }

            _Resgions.Add(key, region);
        }
        public IDataRegion<T> GetRegion(T key)
        {
            if (_Resgions == null)
                throw new InvalidOperationException("there's no region existing.");

            IDataRegion<T> region;
            _Resgions.TryGetValue(key, out region);
            return region;
        }
        public List<IDataRegion<T>> GetRegions()
        {
            return _Resgions.Values.ToList();
        }
        public void ClearRegion()
        {
            this._Resgions.Clear();
        }
        #endregion

        #region helper methods
        private bool NoneInterpreterNeeded(IDataHolder holder)
        {
            return _InterpreterContainer == null || _InterpreterContainer.Count == 0 || !(holder.Data is string);
        }
        private IDataRegion<T> RegionChecking(T key)
        {
            IDataRegion<T> region;
            _Resgions.TryGetValue(key, out region);

            return region;
        }
        protected virtual void FeedingData(IDataHolder holder, IDataRegion<T> region)
        {
            object value = null;
            if (!NoneInterpreterNeeded(holder))
                value = _InterpreterContainer.TryInterpret((string)holder.Data);

            AddInterpretedData(holder, value, region);
        }

        /// <summary>
        /// if value is null, we add the holder directly, otherwise, 
        /// we transform the value into one or more data holders then add them in
        /// </summary>
        /// <param name="holder"></param>
        /// <param name="value"></param>
        /// <param name="region"></param>
        protected abstract void AddInterpretedData(IDataHolder holder, object value, IDataRegion<T> region);
        #endregion
    }
}
